package com.adtech.adms.system.service.impl;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import com.adtech.adms.commons.ErrorCode;
import com.adtech.adms.system.datadictionary.DataDictionaryConstants;
import com.adtech.adms.system.datadictionary.DataDictionaryHelper;
import com.adtech.adms.system.datadictionary.DataItem;
import com.adtech.adms.system.datadictionary.DataType;
import com.adtech.adms.system.datadictionary.dao.DataDictionaryDAO;
import com.adtech.adms.system.datadictionary.pojo.Available;
import com.adtech.adms.system.service.DataDictionaryService;
import com.adtech.core.cache.Cache;
import com.adtech.core.dao.exp.Expression;
import com.adtech.core.dao.query.Pager;
import com.adtech.core.dao.query.QueryConstants;
import com.adtech.core.dao.query.QueryCriterions;
import com.adtech.core.dao.query.Sort;
import com.adtech.core.exception.ReflectException;
import com.adtech.core.exception.ServiceException;
import com.adtech.core.exception.SystemException;
import com.adtech.core.util.ReflectUtil;

/**
 * 数据字典模块service实现类
 * 实现数据字典模块业务操作
 * @author Dormin 
 * @since 2011-6-8 
 * 
 * @Copyright (C) AD Tech Workshop All Right Reserved
 */
public class DataDictionaryServiceImpl implements DataDictionaryService {
	private static Logger log = Logger.getLogger(DataDictionaryServiceImpl.class);
	private DataDictionaryDAO dataDictionaryDAO;
	private Cache cache;

	/**
	 * @param cache the cache to set
	 */
	public void setCache(Cache cache) {
		this.cache = cache;
	}

	public void setDataDictionaryDAO(DataDictionaryDAO dataDictionaryDAO) {
		this.dataDictionaryDAO = dataDictionaryDAO;
	}

	@SuppressWarnings("rawtypes")
	public List<?> getDataList(Pager pager, Expression expression,Sort sort,DataType dataType) throws SystemException {
		if(dataType==null || dataType.getClassName()==null) {
			return null;
		}
		Class entityClass = ReflectUtil.loadClass(dataType.getClassName());
		return dataDictionaryDAO.getByQuery(entityClass, pager, expression, sort);
	}

	@SuppressWarnings("rawtypes")
	public void delete(DataType dataType, String id) throws SystemException {
		Class entityClass = ReflectUtil.loadClass(dataType.getClassName());
		dataDictionaryDAO.deletes(entityClass, id);
		cache.remove(dataType);
	}

	@SuppressWarnings("rawtypes")
	public Object getByTypeAndId(DataType dataType,Long id) throws SystemException {
		Class entityClass = ReflectUtil.loadClass(dataType.getClassName());
		return dataDictionaryDAO.getById(entityClass, id);
	}

	@SuppressWarnings("rawtypes")
	public void save(DataType dataType,Map paramsMap) throws ServiceException, SystemException {
		Class entityClass = ReflectUtil.loadClass(dataType.getClassName());
		try {
			Object obj = entityClass.newInstance();
			for(DataItem item:dataType.getItems()){
				Object fieldValue = setFieldValue(paramsMap, entityClass, obj, item);
				if(item.isUnique()){
					if(checkDuplicate(dataType,item,fieldValue,getIdValue(paramsMap))){
						throw new ServiceException(ErrorCode.DATA_ITEM_DUPLICATE, new Object[]{item.getName()});
					}
				}
			}
			
			dataDictionaryDAO.saveOrUpdate(obj);
			cache.remove(dataType);
		}  catch (ServiceException e) {
			throw e;
		}  catch (Exception e) {
			log.error(e);
		}
	}

	/**
	 * 
	 * @function 从参数map中获取id的值
	 * @param paramsMap 参数map
	 *
	 * @return id
	 * @exception
	 *
	 * @author Dormin
	 * @history
	 *
	 */
	@SuppressWarnings("rawtypes")
	private Long getIdValue(Map paramsMap) {
		Long id = null;
		String[] value = (String[]) paramsMap.get(DataDictionaryConstants.FIELD_ID);
		if(value!=null && value.length>0 && value[0]!=null && value[0].length()>0){
			id = Long.parseLong(value[0]);
		}
		return id;
	}

	/**
	 * 
	 * @function 判断重复
	 * @param dataType 数据分类
	 * @param item 需要验重的字段
	 * @param fieldValue 属性值
	 * @param id
	 *
	 * @return
	 * @throws ClassNotFoundException
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 * @throws InvocationTargetException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @exception
	 *
	 * @author Dormin
	 * @history
	 *
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private boolean checkDuplicate(DataType dataType,DataItem item,Object fieldValue,Long id) throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{
		Class entityClass = Class.forName(dataType.getClassName());
		QueryCriterions hc = new QueryCriterions();
		hc.and(item.getFieldName(), fieldValue, QueryConstants.EQ);
		Object result = dataDictionaryDAO.getOneByQuery(entityClass, hc.toExpression());
		if(result!=null){
			String getIdMethod = DataDictionaryConstants.GET_METHOD_PREFIX+DataDictionaryConstants.FIELD_ID.substring(0, 1).toUpperCase()+DataDictionaryConstants.FIELD_ID.substring(1);
			Method method = entityClass.getMethod(getIdMethod);
			Long oldId = (Long) method.invoke(result);
			if(id!=null){
				if(oldId.longValue()!=id.longValue()){
					return true;
				}
			}
			else{
				return true;
			}
		}
		dataDictionaryDAO.evict(result);
		return false;
	}

	/**
	 * 
	 * @function 利用反射对实体中的各字段赋值
	 * @param paramsMap 参数map
	 * @param entityClass 实体类
	 * @param obj 实体对象
	 * @param item 数据字段
	 *
	 * @return fieldValue 属性值
	 * @exception NoSuchMethodException,IllegalAccessException,InvocationTargetException
	 *
	 * @author Dormin
	 * @throws NoSuchFieldException
	 * @throws SecurityException
	 * @throws ReflectException 
	 * @history
	 *
	 */
	@SuppressWarnings({"rawtypes" })
	private Object setFieldValue(Map paramsMap, Class entityClass, Object obj,
			DataItem item) throws ReflectException, SecurityException, NoSuchFieldException {
		Object fieldValue = null;
		if(item.getFieldName()!=null && item.getFieldName().length()>0){
			Field field = entityClass.getDeclaredField(item.getFieldName());
			String[] value = (String[]) paramsMap.get(item.getFieldName());
			if(value!=null && value.length>0){
				fieldValue = DataDictionaryHelper.parseValue(value[0],field.getType());
				ReflectUtil.setProperty(obj, item.getFieldName(), fieldValue);
			}
		}
		return fieldValue;
	}

	@SuppressWarnings("unchecked")
	public List<Object> getValueList(int typeId) throws SystemException {
		DataType dataType = DataDictionaryHelper.getDataTypeById(typeId);
		List<Object> valueList = (ArrayList<Object>) cache.get(dataType);
		
		if(valueList!=null && valueList.size()>0 ) {
			return valueList;
		}
		
		if(dataType!=null){
			valueList = (List<Object>)dataDictionaryDAO.getListByDataType(dataType);
			cache.put(dataType, (ArrayList<Object>) valueList);
		}
		return valueList;
	}

	public Object getByTypeAndId(int typeId, Long id) throws SystemException {
		DataType dataType = DataDictionaryHelper.getDataTypeById(typeId);
		return getByTypeAndId(dataType,id);
	}

	@SuppressWarnings("rawtypes")
	public Object getByTypeAndField(int typeId, String fieldName, Object fieldValue) throws SystemException {
		DataType dataType = DataDictionaryHelper.getDataTypeById(typeId);
		Class entityClass = ReflectUtil.loadClass(dataType.getClassName());

		QueryCriterions hc = new QueryCriterions();
		hc.and(fieldName.substring(fieldName.indexOf(".")!=-1?fieldName.indexOf(".")+1:0), fieldValue, QueryConstants.EQ);
		Object obj = dataDictionaryDAO.getOneByQuery(entityClass, hc.toExpression());
		
		if (obj instanceof Available && ((Available)obj).isAvailable()) {
			return obj;
		} else {
			return null;
		}
	}
//
//	@SuppressWarnings("rawtypes")
//	public List<?> getListByTypeAndField(int typeId, String fieldName, Object fieldValue) throws SystemException {
//		DataType dataType = DataDictionaryHelper.getDataTypeById(typeId);
//		Class entityClass = ReflectUtil.loadClass(dataType.getClassName());
//		dataDictionaryDAO.setEntityType(entityClass);
//		QueryCriterions hc = new QueryCriterions();
//		hc.and(fieldName, fieldValue, QueryConstants.EQ);
//		return dataDictionaryDAO.getByQuery(hc.toExpression());
//	}

	@Override
	public void enable(DataType dataType, Long id) throws SystemException {
		Object item = getByTypeAndId(dataType, id);
		if (item instanceof Available) {
			((Available)item).setAvailable(true);
		}
		
		dataDictionaryDAO.saveOrUpdate(item);
	}
	
	public void disable(DataType dataType, Long id) throws SystemException {
		Object item = getByTypeAndId(dataType, id);
		if (item instanceof Available) {
			((Available)item).setAvailable(false);
		}
		
		dataDictionaryDAO.saveOrUpdate(item);
	}
}
